import Inula, { Children, cloneElement, createContext, createElement, isValidElement, useContext, useLayoutEffect, useMemo, useRef, useState } from 'react'
import { jsx } from 'openinula/jsx-runtime'

/*
 * Copyright (c) 2023 Huawei Technologies Co.,Ltd.
 *
 * openInula is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *          http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

function isBrowser() {
  return typeof window !== 'undefined' && window.document && typeof window.document.createElement === 'function'
}
function getDefaultConfirmation(message, callBack) {
  callBack(window.confirm(message))
}

// 判断浏览器是否支持pushState方法，pushState是browserHistory实现的基础
function isSupportHistory() {
  return isBrowser() && window.history && 'pushState' in window.history
}

// 判断浏览器是否支持PopState事件
function isSupportsPopState() {
  return !window.navigator.userAgent.includes('Trident')
}

/*
 * Copyright (c) 2023 Huawei Technologies Co.,Ltd.
 *
 * openInula is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *          http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

const Action = /* #__PURE__ */(function (Action) {
  Action.pop = 'POP'
  Action.push = 'PUSH'
  Action.replace = 'REPLACE'
  return Action
}({}))
const EventType = /* #__PURE__ */(function (EventType) {
  EventType.PopState = 'popstate'
  EventType.HashChange = 'hashchange'
  return EventType
}({}))

function _extends() {
  _extends = Object.assign || function (target) {
    for (let i = 1; i < arguments.length; i++) {
      const source = arguments[i]
      for (const key in source) {
        if (Object.prototype.hasOwnProperty.call(source, key))
          target[key] = source[key]
      }
    }
    return target
  }
  return _extends.apply(this, arguments)
}

function createPath(path) {
  const search = path.search
  const hash = path.hash
  let pathname = path.pathname || '/'
  if (search && search !== '?')
    pathname += search.startsWith('?') ? search : `?${search}`

  if (hash && hash !== '#')
    pathname += hash.startsWith('#') ? hash : `#${hash}`

  return pathname
}
function parsePath(url) {
  if (!url)
    return {}

  const parsedPath = {}
  const hashIdx = url.indexOf('#')
  if (hashIdx > -1) {
    parsedPath.hash = url.substring(hashIdx)
    url = url.substring(0, hashIdx)
  }
  const searchIdx = url.indexOf('?')
  if (searchIdx > -1) {
    parsedPath.search = url.substring(searchIdx)
    url = url.substring(0, searchIdx)
  }
  if (url)
    parsedPath.pathname = url

  return parsedPath
}
function createLocation(current, to, state, key) {
  const pathname = typeof current === 'string' ? current : current.pathname
  const urlObj = typeof to === 'string' ? parsePath(to) : to
  // 随机key长度取6
  const getRandKey = genRandomKey(6)
  const location = _extends({
    pathname,
    search: '',
    hash: '',
    state,
    key: typeof key === 'string' ? key : getRandKey(),
  }, urlObj)
  if (!location.pathname)
    location.pathname = '/'

  return location
}
function isLocationEqual(p1, p2) {
  return p1.pathname === p2.pathname && p1.search === p2.search && p1.hash === p2.hash
}
function addHeadSlash(path) {
  if (path[0] === '/')
    return path

  return `/${path}`
}
function stripHeadSlash(path) {
  if (path[0] === '/')
    return path.substring(1)

  return path
}
function normalizeSlash(path) {
  const tempPath = addHeadSlash(path)
  if (tempPath[tempPath.length - 1] === '/')
    return tempPath.substring(0, tempPath.length - 1)

  return tempPath
}
function hasBasename(path, prefix) {
  return path.toLowerCase().indexOf(prefix.toLowerCase()) === 0 && ['/', '?', '#', ''].includes(path.charAt(prefix.length))
}
function stripBasename(path, prefix) {
  return hasBasename(path, prefix) ? path.substring(prefix.length) : path
}

// 使用随机生成的Key记录被访问过的URL，当Block被被触发时利用delta值跳转到之前的页面
function createMemoryRecord(initVal, fn) {
  let visitedRecord = [fn(initVal)]
  function getDelta(to, form) {
    let toIdx = visitedRecord.lastIndexOf(fn(to))
    if (toIdx === -1)
      toIdx = 0

    let fromIdx = visitedRecord.lastIndexOf(fn(form))
    if (fromIdx === -1)
      fromIdx = 0

    return toIdx - fromIdx
  }
  function addRecord(current, newRecord, action) {
    const curVal = fn(current)
    const NewVal = fn(newRecord)
    if (action === Action.push) {
      const prevIdx = visitedRecord.lastIndexOf(curVal)
      const newVisitedRecord = visitedRecord.slice(0, prevIdx + 1)
      newVisitedRecord.push(NewVal)
      visitedRecord = newVisitedRecord
    }
    if (action === Action.replace) {
      const _prevIdx = visitedRecord.lastIndexOf(curVal)
      if (_prevIdx !== -1)
        visitedRecord[_prevIdx] = NewVal
    }
  }
  return {
    getDelta,
    addRecord,
  }
}
function genRandomKey(length) {
  const end = length + 2
  return function () {
    return Math.random().toString(18).substring(2, end)
  }
}

function _classCallCheck(instance, Constructor) {
  if (!(instance instanceof Constructor))
    throw new TypeError('Cannot call a class as a function')
}

function _defineProperties(target, props) {
  for (let i = 0; i < props.length; i++) {
    const descriptor = props[i]
    descriptor.enumerable = descriptor.enumerable || false
    descriptor.configurable = true
    if ('value' in descriptor)
      descriptor.writable = true
    Object.defineProperty(target, descriptor.key, descriptor)
  }
}
function _createClass(Constructor, protoProps, staticProps) {
  if (protoProps)
    _defineProperties(Constructor.prototype, protoProps)
  if (staticProps)
    _defineProperties(Constructor, staticProps)
  Object.defineProperty(Constructor, 'prototype', {
    writable: false,
  })
  return Constructor
}

function _createForOfIteratorHelper$1(o, allowArrayLike) {
  let it = typeof Symbol !== 'undefined' && o[Symbol.iterator] || o['@@iterator']; if (!it) {
    if (Array.isArray(o) || (it = _unsupportedIterableToArray$1(o)) || allowArrayLike && o && typeof o.length === 'number') {
      if (it)
        o = it; let i = 0; const F = function () {}; return { s: F, n() {
        if (i >= o.length)
          return { done: true }; return { done: false, value: o[i++] }
      }, e(e) { throw e }, f: F }
    } throw new TypeError('Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.')
  } let normalCompletion = true; let didErr = false; let err; return { s() { it = it.call(o) }, n() { const step = it.next(); normalCompletion = step.done; return step }, e(e) { didErr = true; err = e }, f() {
    try {
      if (!normalCompletion && it.return != null)
        it.return()
    }
    finally {
      if (didErr)
        throw err
    }
  } }
}
function _unsupportedIterableToArray$1(o, minLen) {
  if (!o)
    return; if (typeof o === 'string')
    return _arrayLikeToArray$1(o, minLen); let n = Object.prototype.toString.call(o).slice(8, -1); if (n === 'Object' && o.constructor)
    n = o.constructor.name; if (n === 'Map' || n === 'Set')
    return Array.from(o); if (n === 'Arguments' || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))
    return _arrayLikeToArray$1(o, minLen)
}
function _arrayLikeToArray$1(arr, len) {
  if (len == null || len > arr.length)
    len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2
}
/*
 * Copyright (c) 2023 Huawei Technologies Co.,Ltd.
 *
 * openInula is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *          http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
const TransitionManager = /* #__PURE__ */(function () {
  function TransitionManager() {
    _classCallCheck(this, TransitionManager)
    this.prompt = void 0
    this.listeners = void 0
    this.prompt = null
    this.listeners = []
  }
  _createClass(TransitionManager, [{
    key: 'setPrompt',
    value: function setPrompt(prompt) {
      const _this = this
      this.prompt = prompt

      // 清除Prompt
      return function () {
        if (_this.prompt === prompt)
          _this.prompt = null
      }
    },

    // 使用发布订阅模式管理history的监听者
  }, {
    key: 'addListener',
    value: function addListener(func) {
      const _this2 = this
      let isActive = true
      const listener = function (args) {
        if (isActive)
          func(args)
      }
      this.listeners.push(listener)
      return function () {
        isActive = false
        // 移除对应的监听者
        _this2.listeners = _this2.listeners.filter((item) => {
          return item !== listener
        })
      }
    },
  }, {
    key: 'notifyListeners',
    value: function notifyListeners(args) {
      const _iterator = _createForOfIteratorHelper$1(this.listeners)
      let _step
      try {
        for (_iterator.s(); !(_step = _iterator.n()).done;) {
          const listener = _step.value
          listener(args)
        }
      }
      catch (err) {
        _iterator.e(err)
      }
      finally {
        _iterator.f()
      }
    },
  }, {
    key: 'confirmJumpTo',
    value: function confirmJumpTo(location, action, userConfirmationFunc, callBack) {
      if (this.prompt !== null) {
        const result = typeof this.prompt === 'function' ? this.prompt(location, action) : this.prompt
        if (typeof result === 'string')
          typeof userConfirmationFunc === 'function' ? userConfirmationFunc(result, callBack) : callBack(true)
        else
          callBack(result !== false)
      }
      else {
        callBack(true)
      }
    },
  }])
  return TransitionManager
}())

/*
 * Copyright (c) 2023 Huawei Technologies Co.,Ltd.
 *
 * openInula is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *          http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

function warning(condition, message) {
  if (condition) {
    if (console && typeof console.warn === 'function')
      console.warn(message)
  }
}

/*
 * Copyright (c) 2023 Huawei Technologies Co.,Ltd.
 *
 * openInula is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *          http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

// 抽取BrowserHistory和HashHistory中相同的方法
function getBaseHistory(transitionManager, setListener, browserHistory) {
  function go(step) {
    browserHistory.go(step)
  }
  function goBack() {
    browserHistory.go(-1)
  }
  function goForward() {
    browserHistory.go(1)
  }
  function listen(listener) {
    const cancel = transitionManager.addListener(listener)
    setListener(1)
    return function () {
      setListener(-1)
      cancel()
    }
  }
  let isBlocked = false
  function block() {
    const prompt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false
    const unblock = transitionManager.setPrompt(prompt)
    if (!isBlocked) {
      setListener(1)
      isBlocked = true
    }
    return function () {
      if (isBlocked) {
        isBlocked = false
        setListener(-1)
      }
      unblock()
    }
  }
  function getUpdateStateFunc(historyProps) {
    return function (nextState) {
      if (nextState)
        _extends(historyProps, nextState)

      historyProps.length = browserHistory.length
      const args = {
        location: historyProps.location,
        action: historyProps.action,
      }
      transitionManager.notifyListeners(args)
    }
  }
  return {
    go,
    goBack,
    goForward,
    listen,
    block,
    getUpdateStateFunc,
  }
}

/*
 * Copyright (c) 2023 Huawei Technologies Co.,Ltd.
 *
 * openInula is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *          http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
function createBrowserHistory() {
  const options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}
  const supportHistory = isSupportHistory()
  const isSupportPopState = isSupportsPopState()
  const browserHistory = window.history
  const _options$forceRefresh = options.forceRefresh
  const forceRefresh = _options$forceRefresh === void 0 ? false : _options$forceRefresh
  const _options$getUserConfi = options.getUserConfirmation
  const getUserConfirmation = _options$getUserConfi === void 0 ? getDefaultConfirmation : _options$getUserConfi
  const basename = options.basename ? normalizeSlash(options.basename) : ''
  const initLocation = getLocation(getHistoryState())
  const recordOperator = createMemoryRecord(initLocation, (l) => {
    return l.key
  })
  const transitionManager = new TransitionManager()
  const _getBaseHistory = getBaseHistory(transitionManager, setListener, browserHistory)
  const go = _getBaseHistory.go
  const goBack = _getBaseHistory.goBack
  const goForward = _getBaseHistory.goForward
  const listen = _getBaseHistory.listen
  const block = _getBaseHistory.block
  const getUpdateStateFunc = _getBaseHistory.getUpdateStateFunc
  const history = {
    action: Action.pop,
    length: browserHistory.length,
    location: initLocation,
    go,
    goBack,
    goForward,
    listen,
    block,
    push,
    replace,
    createHref,
  }
  const updateState = getUpdateStateFunc(history)
  function getHistoryState() {
    return supportHistory ? window.history.state : {}
  }
  function getLocation(historyState) {
    const _window$location = window.location
    const search = _window$location.search
    const hash = _window$location.hash
    const _ref = historyState || {}
    const key = _ref.key
    const state = _ref.state
    let pathname = window.location.pathname
    pathname = basename ? stripBasename(pathname, basename) : pathname
    return createLocation('', {
      pathname,
      search,
      hash,
    }, state, key)
  }

  // 拦截页面POP事件后，防止返回到的页面被重复拦截
  let forceJump = false
  function handlePopState(location) {
    if (forceJump) {
      forceJump = false
      updateState(undefined)
    }
    else {
      const action = Action.pop
      const callback = function (isJump) {
        if (isJump) {
          // 执行跳转行为
          updateState({
            action,
            location,
          })
        }
        else {
          revertPopState(location, history.location)
        }
      }
      transitionManager.confirmJumpTo(location, action, getUserConfirmation, callback)
    }
  }
  function popStateListener(event) {
    handlePopState(getLocation(event.state))
  }
  function hashChangeListener() {
    const location = getLocation(getHistoryState())
    handlePopState(location)
  }
  let listenerCount = 0
  function setListener(count) {
    listenerCount += count
    if (listenerCount === 1 && count === 1) {
      window.addEventListener(EventType.PopState, popStateListener)
      if (!isSupportPopState)
        window.addEventListener(EventType.HashChange, hashChangeListener)
    }
    else if (listenerCount === 0) {
      window.removeEventListener(EventType.PopState, popStateListener)
      if (!isSupportPopState)
        window.removeEventListener(EventType.HashChange, hashChangeListener)
    }
  }

  // 取消页面跳转并恢复到跳转前的页面
  function revertPopState(form, to) {
    const delta = recordOperator.getDelta(to, form)
    if (delta !== 0) {
      go(delta)
      forceJump = true
    }
  }
  function createHref(path) {
    return basename + createPath(path)
  }
  function push(to, state) {
    const action = Action.push
    const location = createLocation(history.location, to, state, undefined)
    transitionManager.confirmJumpTo(location, action, getUserConfirmation, (isJump) => {
      if (!isJump)
        return

      const href = createHref(location)
      const key = location.key
      const state = location.state
      if (supportHistory) {
        if (forceRefresh) {
          window.location.href = href
        }
        else {
          browserHistory.pushState({
            key,
            state,
          }, '', href)
          recordOperator.addRecord(history.location, location, action)
          updateState({
            action,
            location,
          })
        }
      }
      else {
        warning(state !== undefined, 'Browser history cannot push state in browsers that do not support HTML5 history')
        window.location.href = href
      }
    })
  }
  function replace(to, state) {
    const action = Action.replace
    const location = createLocation(history.location, to, state, undefined)
    transitionManager.confirmJumpTo(location, action, getUserConfirmation, (isJump) => {
      if (!isJump)
        return

      const href = createHref(location)
      const key = location.key
      const state = location.state
      if (supportHistory) {
        if (forceRefresh) {
          window.location.replace(href)
        }
        else {
          browserHistory.replaceState({
            key,
            state,
          }, '', href)
          recordOperator.addRecord(history.location, location, action)
          updateState({
            action,
            location,
          })
        }
      }
      else {
        warning(state !== undefined, 'Browser history cannot push state in browsers that do not support HTML5 history')
        window.location.replace(href)
      }
    })
  }
  return history
}

/*
 * Copyright (c) 2023 Huawei Technologies Co.,Ltd.
 *
 * openInula is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *          http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
// 获取#前的内容
function stripHash(path) {
  const idx = path.indexOf('#')
  return idx === -1 ? path : path.substring(0, idx)
}

// 获取#后的内容
function getHashContent(path) {
  const idx = path.indexOf('#')
  return idx === -1 ? '' : path.substring(idx + 1)
}
function createHashHistory() {
  const option = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}
  const browserHistory = window.history
  const _option$hashType = option.hashType
  const hashType = _option$hashType === void 0 ? 'slash' : _option$hashType
  const _option$getUserConfir = option.getUserConfirmation
  const getUserConfirmation = _option$getUserConfir === void 0 ? getDefaultConfirmation : _option$getUserConfir
  const basename = option.basename ? normalizeSlash(option.basename) : ''
  const pathDecoder = addHeadSlash
  const pathEncoder = hashType === 'slash' ? addHeadSlash : stripHeadSlash
  function getLocation() {
    let hashPath = pathDecoder(getHashContent(window.location.hash))
    if (basename)
      hashPath = stripBasename(hashPath, basename)

    return createLocation('', hashPath, undefined, 'default')
  }
  const initLocation = getLocation()
  const memRecords = createMemoryRecord(initLocation, createPath)
  const transitionManager = new TransitionManager()
  function createHref(location) {
    const tag = document.querySelector('base')
    const base = tag && tag.getAttribute('href') ? stripHash(window.location.href) : ''
    return `${base}#${pathEncoder(basename + createPath(location))}`
  }
  let forceNextPop = false
  let ignorePath = null
  const _getBaseHistory = getBaseHistory(transitionManager, setListener, browserHistory)
  const go = _getBaseHistory.go
  const goBack = _getBaseHistory.goBack
  const goForward = _getBaseHistory.goForward
  const listen = _getBaseHistory.listen
  const block = _getBaseHistory.block
  const getUpdateStateFunc = _getBaseHistory.getUpdateStateFunc
  const history = {
    action: Action.pop,
    length: browserHistory.length,
    location: initLocation,
    go,
    goBack,
    goForward,
    push,
    replace,
    listen,
    block,
    createHref,
  }
  const updateState = getUpdateStateFunc(history)
  function push(to, state) {
    warning(state !== undefined, 'Hash history does not support state, it will be ignored')
    const action = Action.push
    const location = createLocation(history.location, to, undefined, '')
    transitionManager.confirmJumpTo(location, action, getUserConfirmation, (isJump) => {
      if (!isJump)
        return

      const path = createPath(location)
      const encodedPath = pathEncoder(basename + path)
      // 前后hash不一样才进行跳转
      if (getHashContent(window.location.href) !== encodedPath) {
        ignorePath = encodedPath
        window.location.hash = encodedPath
        memRecords.addRecord(history.location, location, action)
        updateState({
          action,
          location,
        })
      }
      else {
        updateState(undefined)
      }
    })
  }
  function replace(to, state) {
    warning(state !== undefined, 'Hash history does not support state, it will be ignored')
    const action = Action.replace
    const location = createLocation(history.location, to, undefined, '')
    transitionManager.confirmJumpTo(location, action, getUserConfirmation, (isJump) => {
      if (!isJump)
        return

      const path = createPath(location)
      const encodedPath = pathEncoder(basename + path)
      if (getHashContent(window.location.href) !== encodedPath) {
        ignorePath = path
        window.location.replace(`${stripHash(window.location.href)}#${encodedPath}`)
      }
      memRecords.addRecord(history.location, location, action)
      updateState({
        action,
        location,
      })
    })
  }
  function handleHashChange() {
    const hashPath = getHashContent(window.location.href)
    const encodedPath = pathEncoder(hashPath)
    if (hashPath !== encodedPath) {
      window.location.replace(`${stripHash(window.location.href)}#${encodedPath}`)
    }
    else {
      const location = getLocation()
      const prevLocation = history.location
      if (!forceNextPop && isLocationEqual(location, prevLocation))
        return

      if (ignorePath === createPath(location))
        return

      ignorePath = null
      handlePopState(location)
    }
  }
  function handlePopState(location) {
    if (forceNextPop) {
      forceNextPop = false
      updateState(undefined)
    }
    else {
      const action = Action.pop
      const callback = function (isJump) {
        if (isJump) {
          updateState({
            action,
            location,
          })
        }
        else {
          revertPopState(location)
        }
      }
      transitionManager.confirmJumpTo(location, action, getUserConfirmation, callback)
    }
  }

  // 在跳转行为被Block后，用History.go()跳转回之前的页面
  function revertPopState(form) {
    const to = history.location
    const delta = memRecords.getDelta(to, form)
    if (delta !== 0) {
      go(delta)
      forceNextPop = true
    }
  }
  let listenerCount = 0
  function setListener(delta) {
    listenerCount += delta
    if (listenerCount === 1 && delta === 1)
      window.addEventListener(EventType.HashChange, handleHashChange)
    else if (listenerCount === 0)
      window.removeEventListener(EventType.HashChange, handleHashChange)
  }
  return history
}

/*
 * Copyright (c) 2023 Huawei Technologies Co.,Ltd.
 *
 * openInula is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *          http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
function createNamedContext(name, defaultValue) {
  const context = createContext(defaultValue)
  context.displayName = name
  return context
}
const RouterContext = createNamedContext('Router', {})

/*
 * Copyright (c) 2023 Huawei Technologies Co.,Ltd.
 *
 * openInula is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *          http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

const TokenType = /* #__PURE__ */(function (TokenType) {
  TokenType.Delimiter = 'delimiter'
  TokenType.Static = 'static'
  TokenType.Param = 'param'
  TokenType.WildCard = 'wildcard'
  TokenType.LBracket = '('
  TokenType.RBracket = ')'
  TokenType.Pattern = 'pattern'
  return TokenType
}({}))

// 解析URL中的动态参数，以实现TypeScript提示功能

/*
 * Copyright (c) 2023 Huawei Technologies Co.,Ltd.
 *
 * openInula is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *          http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

/**
 * @description 将url中的//转换为/
 */
function cleanPath(path) {
  return path.replace(/\/+/g, '/')
}
function scoreCompare(score1, score2) {
  const score1Length = score1.length
  const score2Length = score2.length
  const end = Math.min(score1Length, score2Length)
  for (let i = 0; i < end; i++) {
    const delta = score2[i] - score1[i]
    if (delta !== 0)
      return delta
  }
  if (score1Length === score2Length)
    return 0

  return score1Length > score2Length ? -1 : 1
}

// 把正则表达式的特殊符号加两个反斜杠进行转义
function escapeStr(str) {
  return str.replace(/([.+*?=^!:${}()[\]|/\\])/g, '\\$1')
}

/*
 * Copyright (c) 2023 Huawei Technologies Co.,Ltd.
 *
 * openInula is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *          http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
const validChar = /[^/:()*?$^+]/

// 对Url模板进行词法解析，解析结果为Tokens
function lexer(path) {
  const tokens = []
  if (!path)
    return tokens

  const urlPath = cleanPath(path)
  if (urlPath !== '*' && !urlPath.startsWith('/'))
    throw new Error('Url must start with "/".')

  const getLiteral = function () {
    let name = ''
    while (i < urlPath.length && validChar.test(urlPath[i])) {
      name += urlPath[i]
      skipChar(1)
    }
    return name
  }
  var skipChar = function (step) {
    i += step
  }
  var i = 0
  while (i < urlPath.length) {
    const curChar = urlPath[i]
    const prevChar = urlPath[i - 1]
    if (curChar === '/') {
      tokens.push({
        type: TokenType.Delimiter,
        value: urlPath[i],
      })
      skipChar(1)
      continue
    }
    // dynamic params (/:a)
    if (prevChar === '/' && curChar === ':') {
      skipChar(1)
      tokens.push({
        type: TokenType.Param,
        value: getLiteral(),
      })
      continue
    }
    // wildCard params (/:*)
    if ((prevChar === '/' || prevChar === undefined) && curChar === '*') {
      tokens.push({
        type: TokenType.WildCard,
        value: urlPath[i],
      })
      skipChar(1)
      continue
    }
    // static params
    if (prevChar === '/' && validChar.test(curChar)) {
      tokens.push({
        type: TokenType.Static,
        value: getLiteral(),
      })
      continue
    }
    if (curChar === '(') {
      tokens.push({
        type: TokenType.LBracket,
        value: '(',
      })
      skipChar(1)
      continue
    }
    if (curChar === ')') {
      tokens.push({
        type: TokenType.RBracket,
        value: ')',
      })
      skipChar(1)
      continue
    }
    if (['*', '?', '$', '^', '+'].includes(curChar)) {
      tokens.push({
        type: TokenType.Pattern,
        value: curChar,
      })
      skipChar(1)
      continue
    }
    if (validChar.test(curChar)) {
      tokens.push({
        type: TokenType.Pattern,
        value: getLiteral(),
      })
      continue
    }
    // 跳过非法字符
    skipChar(1)
  }
  return tokens
}

function _createForOfIteratorHelper(o, allowArrayLike) {
  let it = typeof Symbol !== 'undefined' && o[Symbol.iterator] || o['@@iterator']; if (!it) {
    if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === 'number') {
      if (it)
        o = it; let i = 0; const F = function () {}; return { s: F, n() {
        if (i >= o.length)
          return { done: true }; return { done: false, value: o[i++] }
      }, e(e) { throw e }, f: F }
    } throw new TypeError('Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.')
  } let normalCompletion = true; let didErr = false; let err; return { s() { it = it.call(o) }, n() { const step = it.next(); normalCompletion = step.done; return step }, e(e) { didErr = true; err = e }, f() {
    try {
      if (!normalCompletion && it.return != null)
        it.return()
    }
    finally {
      if (didErr)
        throw err
    }
  } }
}
function _unsupportedIterableToArray(o, minLen) {
  if (!o)
    return; if (typeof o === 'string')
    return _arrayLikeToArray(o, minLen); let n = Object.prototype.toString.call(o).slice(8, -1); if (n === 'Object' && o.constructor)
    n = o.constructor.name; if (n === 'Map' || n === 'Set')
    return Array.from(o); if (n === 'Arguments' || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))
    return _arrayLikeToArray(o, minLen)
}
function _arrayLikeToArray(arr, len) {
  if (len == null || len > arr.length)
    len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2
}

// 不同类型参数的匹配得分
var MatchScore = /* #__PURE__ */(function (MatchScore) {
  MatchScore[MatchScore.static = 10] = 'static'
  MatchScore[MatchScore.param = 6] = 'param'
  MatchScore[MatchScore.wildcard = 3] = 'wildcard'
  MatchScore[MatchScore.placeholder = -1] = 'placeholder'
  return MatchScore
}(MatchScore || {}))
const defaultOption = {
  // url匹配时是否大小写敏感
  caseSensitive: true,
  // 是否严格匹配url结尾的/
  strictMode: false,
  // 是否完全精确匹配
  exact: false,
}
// 正则表达式中需要转义的字符
const REGEX_CHARS_RE = /[.+*?^${}()[\]/\\]/g
// 用于匹配两个//中的的值
const BASE_PARAM_PATTERN = '[^/]+'
const DefaultDelimiter = '/#?'

/**
 * URL匹配整体流程
 * 1.词法解析，将URL模板解析为Token
 * 2.使用Token生成正则表达式
 * 3.利用正则表达式解析URL中参数或填充URL模板
 */

function createPathParser(pathname) {
  const option = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultOption
  const _option$caseSensitive = option.caseSensitive
  const caseSensitive = _option$caseSensitive === void 0 ? defaultOption.caseSensitive : _option$caseSensitive
  const _option$strictMode = option.strictMode
  const strictMode = _option$strictMode === void 0 ? defaultOption.strictMode : _option$strictMode
  const _option$exact = option.exact
  const exact = _option$exact === void 0 ? defaultOption.exact : _option$exact
  let pattern = '^'
  const keys = []
  const scores = []
  const tokens = lexer(pathname)
  const onlyHasWildCard = tokens.length === 1 && tokens[0].type === TokenType.WildCard
  const tokenCount = tokens.length
  const lastToken = tokens[tokenCount - 1]
  let asteriskCount = 0

  /**
   * 用于支持URL中的可选参数/:parma?
   * @description 向前扫描到下一个分隔符/，检查其中是否有?
   * @param currentIdx
   */
  const lookToNextDelimiter = function (currentIdx) {
    let hasOptionalParam = false
    while (currentIdx < tokens.length && tokens[currentIdx].type !== TokenType.Delimiter) {
      if (tokens[currentIdx].value === '?' || tokens[currentIdx].value === '*')
        hasOptionalParam = true

      currentIdx++
    }
    return hasOptionalParam
  }
  for (let tokenIdx = 0; tokenIdx < tokenCount; tokenIdx++) {
    const token = tokens[tokenIdx]
    const nextToken = tokens[tokenIdx + 1]
    switch (token.type) {
      case TokenType.Delimiter:
        var hasOptional = lookToNextDelimiter(tokenIdx + 1)
        pattern += `/${hasOptional ? '?' : ''}`
        break
      case TokenType.Static:
        pattern += token.value.replace(REGEX_CHARS_RE, '\\$&')
        if (nextToken && nextToken.type === TokenType.Pattern) {
          pattern += `(.${nextToken.value})`
          keys.push(String(asteriskCount))
          asteriskCount++
        }
        scores.push(MatchScore.static)
        break
      case TokenType.Param:
        // 动态参数支持形如/:param、/:param*、/:param?、/:param(\\d+)的形式
        var paramRegexp = ''
        if (nextToken) {
          switch (nextToken.type) {
            case TokenType.LBracket:
              // 跳过当前Token和左括号
              tokenIdx += 2
              while (tokens[tokenIdx].type !== TokenType.RBracket) {
                paramRegexp += tokens[tokenIdx].value
                tokenIdx++
              }
              paramRegexp = `(${paramRegexp})`
              break
            case TokenType.Pattern:
              tokenIdx++
              paramRegexp += `(${nextToken.value === '*' ? '.*' : BASE_PARAM_PATTERN})${nextToken.value}`
              break
          }
        }
        pattern += paramRegexp ? `(?:${paramRegexp})` : `(${BASE_PARAM_PATTERN})`
        keys.push(token.value)
        scores.push(MatchScore.param)
        break
      case TokenType.WildCard:
        keys.push(token.value)
        pattern += `((?:${BASE_PARAM_PATTERN})${onlyHasWildCard ? '?' : ''}(?:/(?:${BASE_PARAM_PATTERN}))*)`
        scores.push(onlyHasWildCard ? MatchScore.wildcard : MatchScore.placeholder)
        break
    }
  }
  const isWildCard = lastToken.type === TokenType.WildCard
  if (!isWildCard && !exact) {
    if (!strictMode)
      pattern += `(?:[${escapeStr(DefaultDelimiter)}](?=$))?`

    if (lastToken.type !== TokenType.Delimiter)
      pattern += `(?=[${escapeStr(DefaultDelimiter)}]|$)`
  }
  else {
    pattern += strictMode ? '$' : `[${escapeStr(DefaultDelimiter)}]?$`
  }
  const flag = caseSensitive ? '' : 'i'
  const regexp = new RegExp(pattern, flag)

  /**
   * @description 根据给定Pattern解析path
   */
  function parse(path) {
    const reMatch = path.match(regexp)
    if (!reMatch)
      return null

    const matchedPath = reMatch[0]
    const params = {}
    const parseScore = Array.from(scores)
    for (let i = 1; i < reMatch.length; i++) {
      const param = reMatch[i]
      const key = keys[i - 1]
      if (key === '*' && param) {
        const value = param.split('/')
        if (!Array.isArray(params['*'])) {
          params['*'] = value
        }
        else {
          var _params$;
          (_params$ = params['*']).push.apply(_params$, value)
        }
        // 完成通配符参数解析后将placeholder替换为wildcard参数的分值
        parseScore.splice.apply(parseScore, [scores.indexOf(MatchScore.placeholder), 1].concat(Array.from({ length: value.length }).fill(MatchScore.wildcard)))
      }
      else {
        params[key] = param || undefined
      }
    }
    const isExact = path === matchedPath
    const url = path === '/' && matchedPath === '' ? '/' : matchedPath
    return {
      isExact,
      path: pathname,
      url,
      score: parseScore,
      params,
    }
  }

  /**
   * @description 使用给定参数填充pattern，得到目标URL
   */
  function compile(params) {
    let path = ''
    const _iterator = _createForOfIteratorHelper(tokens)
    let _step
    try {
      for (_iterator.s(); !(_step = _iterator.n()).done;) {
        const _token = _step.value
        switch (_token.type) {
          case TokenType.Static:
            path += _token.value
            break
          case TokenType.Param:
            if (!params[_token.value])
              throw new Error('Param is invalid.')

            path += params[_token.value]
            break
          case TokenType.WildCard:
            var wildCard = params['*']
            if (Array.isArray(wildCard))
              path += wildCard.join('/')
            else
              path += wildCard

            break
          case TokenType.Delimiter:
            path += _token.value
            break
        }
      }
    }
    catch (err) {
      _iterator.e(err)
    }
    finally {
      _iterator.f()
    }
    return path
  }
  return {
    get regexp() {
      return regexp
    },
    get keys() {
      return keys
    },
    compile,
    parse,
  }
}

/**
 * @description 依次使用pathname与pattern进行匹配，根据匹配分数取得分数最高结果
 */
function matchPath(pathname, pattern, option) {
  const patterns = Array.isArray(pattern) ? [].concat(pattern) : [pattern]
  const matchedResults = []
  const _iterator2 = _createForOfIteratorHelper(patterns)
  let _step2
  try {
    for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
      const item = _step2.value
      const parser = createPathParser(item, option)
      const matched = parser.parse(pathname)
      if (matched)
        matchedResults.push(matched)
    }
  }
  catch (err) {
    _iterator2.e(err)
  }
  finally {
    _iterator2.f()
  }
  return !matchedResults.length
    ? null
    : matchedResults.sort((a, b) => {
      return scoreCompare(a.score, b.score)
    })[0]
}
function generatePath(path, params) {
  const parser = createPathParser(path)
  return parser.compile(params)
}

/*
 * Copyright (c) 2023 Huawei Technologies Co.,Ltd.
 *
 * openInula is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *          http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
function useHistory() {
  return useContext(RouterContext).history
}
function useLocation() {
  return useContext(RouterContext).location
}
function useParams() {
  const match = useContext(RouterContext).match
  return match ? match.params : {}
}
function useRouteMatch(path) {
  const pathname = useLocation().pathname
  const match = useContext(RouterContext).match
  if (path)
    return matchPath(pathname, path)

  return match
}

function Route(props) {
  const context = useContext(RouterContext)
  const computed = props.computed
  const location = props.location
  const path = props.path
  let children = props.children
  const component = props.component
  const render = props.render
  let match
  const routeLocation = location || context.location
  if (computed)
    match = computed
  else if (path)
    match = matchPath(routeLocation.pathname, path)
  else
    match = context.match

  const newProps = _extends({}, context, {
    location: routeLocation,
    match,
  })
  if (Array.isArray(children) && Children.count(children) === 0)
    children = null

  /**
   * 按顺序获取需要渲染的组件
   * 1.children
   * 2.component
   * 3.render
   * 都没有匹配到返回Null
   */
  const getChildren = function () {
    // 如果 match 存在
    if (newProps.match) {
      if (children) {
        if (typeof children === 'function')
          return children(newProps)

        return children
      }
      if (component)
        return createElement(component, newProps)
      else if (render)
        return render(newProps)
      else
        return null
    }
    else {
      // match为null
      if (typeof children === 'function')
        return children(newProps)

      return null
    }
  }
  return jsx(RouterContext.Provider, {
    value: newProps,
    children: getChildren(),
  })
}

/*
 * Copyright (c) 2023 Huawei Technologies Co.,Ltd.
 *
 * openInula is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *          http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
function Router(props) {
  const history = props.history
  const _props$children = props.children
  const children = _props$children === void 0 ? null : _props$children
  const _useState = useState(props.history.location)
  const location = _useState[0]
  const setLocation = _useState[1]
  console.log('location:', location)
  const pendingLocation = useRef(null)

  // 在Router加载时就监听history地址变化，以保证在始渲染时重定向能正确触发
  const unListen = useRef(history.listen((arg) => {
    pendingLocation.current = arg.location
  }))

  // 模拟componentDidMount和componentWillUnmount
  useLayoutEffect(() => {
    if (unListen.current)
      unListen.current()

    // 监听history中的位置变化
    unListen.current = history.listen((arg) => {
      setLocation(arg.location)
    })
    if (pendingLocation.current)
      setLocation(pendingLocation.current)

    return function () {
      if (unListen.current) {
        unListen.current()
        unListen.current = null
        pendingLocation.current = null
      }
    }
  }, [])
  const initContextValue = useMemo(() => {
    return {
      history,
      location,
      match: {
        isExact: location.pathname === '/',
        params: {},
        path: '/',
        score: [],
        url: '/',
      },
    }
  }, [location])
  return jsx(RouterContext.Provider, {
    value: initContextValue,
    children,
  })
}

function _objectWithoutPropertiesLoose(source, excluded) {
  if (source == null)
    return {}
  const target = {}
  const sourceKeys = Object.keys(source)
  let key, i
  for (i = 0; i < sourceKeys.length; i++) {
    key = sourceKeys[i]
    if (excluded.includes(key))
      continue
    target[key] = source[key]
  }
  return target
}

/*
 * Copyright (c) 2023 Huawei Technologies Co.,Ltd.
 *
 * openInula is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *          http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
function LifeCycle(props) {
  // 使用ref保存上一次的props，防止重新渲染
  const prevProps = useRef(null)
  const isMount = useRef(false)
  const onMount = props.onMount
  const onUpdate = props.onUpdate
  const onUnmount = props.onUnmount
  useLayoutEffect(() => {
    // 首次挂载 模拟componentDidMount
    if (!isMount.current) {
      isMount.current = true
      if (onMount)
        onMount()
    }
    else {
      // 不是首次渲染 模拟componentDidUpdate
      if (onUpdate)
        prevProps.current ? onUpdate(prevProps.current) : onUpdate()
    }
    prevProps.current = props
  })

  // 模拟componentWillUnmount
  useLayoutEffect(() => {
    return function () {
      if (onUnmount)
        onUnmount()
    }
  }, [])
  return null
}

const _excluded$2 = ['state']
function Redirect(props) {
  const to = props.to
  const _props$push = props.push
  const push = _props$push === void 0 ? false : _props$push
  const computed = props.computed
  const context = useContext(RouterContext)
  const history = context.history
  const calcLocation = function () {
    if (computed) {
      if (typeof to === 'string') {
        const parser = createPathParser(to)
        const target = parser.compile(computed.params)
        return parsePath(target)
      }
      else {
        const pathname = to.pathname ? addHeadSlash(to.pathname) : '/'
        const _parser = createPathParser(pathname)
        const _target = _parser.compile(computed.params)
        return _extends({}, to, {
          pathname: _target,
        })
      }
    }
    return typeof to === 'string' ? parsePath(to) : to
  }
  const navigate = push ? history.push : history.replace
  const _calcLocation = calcLocation()
  const state = _calcLocation.state
  const path = _objectWithoutPropertiesLoose(_calcLocation, _excluded$2)
  const onMountFunc = function () {
    navigate(path, state)
  }
  const onUpdateFunc = function (prevProps) {
    // 如果当前页面与重定向前页面不一致，执行跳转
    const prevPath = prevProps === null || prevProps === void 0 ? void 0 : prevProps.data
    if (!isLocationEqual(prevPath, path))
      navigate(path, state)
  }
  return jsx(LifeCycle, {
    onMount: onMountFunc,
    onUpdate: onUpdateFunc,
    data: path,
  })
}

/*
 * Copyright (c) 2023 Huawei Technologies Co.,Ltd.
 *
 * openInula is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *          http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
function Switch(props) {
  const context = useContext(RouterContext)
  const location = props.location || context.location
  let element = null
  let match = null

  // 使用forEach不会给InulaNode增加key属性,防止重新渲染
  Children.forEach(props.children, (node) => {
    if (match === null && isValidElement(node)) {
      element = node
      let strict
      let sensitive
      let path
      let from

      // node可能是Route和Redirect
      if (node.type === Route) {
        const _ref = node.props
        strict = _ref.strict
        sensitive = _ref.sensitive
        path = _ref.path
      }
      else if (node.type === Redirect) {
        const _ref2 = node.props
        path = _ref2.path
        strict = _ref2.strict
        from = _ref2.from
      }
      const exact = node.props.exact
      const target = path || from

      // 更新匹配状态，一旦匹配到停止遍历
      if (target) {
        match = matchPath(location.pathname, target, {
          strictMode: strict,
          caseSensitive: sensitive,
          exact,
        })
      }
      else {
        match = context.match
      }
    }
  })
  if (match && element) {
    // 使用cloneElement复制已有组件并更新其Props
    return cloneElement(element, {
      location,
      computed: match,
    })
  }
  return null
}

/*
 * Copyright (c) 2023 Huawei Technologies Co.,Ltd.
 *
 * openInula is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *          http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
function Prompt(props) {
  const context = useContext(RouterContext)
  const message = props.message
  const _props$when = props.when
  const when = _props$when === void 0 ? true : _props$when
  if (typeof when === 'function' && when(context.location) === false || !when)
    return null

  const navigate = context.history.block
  let release = null
  const onMountFunc = function () {
    release = message ? navigate(message) : null
  }
  const onUpdateFunc = function (prevProps) {
    if (prevProps && prevProps.data !== message) {
      if (release)
        release()

      release = message ? navigate(message) : null
    }
  }
  const onUnmountFunc = function () {
    if (release)
      release()

    release = null
  }
  return jsx(LifeCycle, {
    onMount: onMountFunc,
    onUpdate: onUpdateFunc,
    onUnmount: onUnmountFunc,
    data: message,
  })
}

function withRouter(Component) {
  function ComponentWithRouterProp(props) {
    const _useContext = useContext(RouterContext)
    const history = _useContext.history
    const location = _useContext.location
    const match = _useContext.match
    const routeProps = {
      history,
      location,
      match,
    }
    return jsx(Component, _extends({}, props, routeProps))
  }
  return ComponentWithRouterProp
}

/*
 * Copyright (c) 2023 Huawei Technologies Co.,Ltd.
 *
 * openInula is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *          http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
function HashRouter(props) {
  const historyRef = useRef()
  if (historyRef.current === null || historyRef.current === undefined) {
    historyRef.current = createHashHistory({
      basename: props.basename,
      getUserConfirmation: props.getUserConfirmation,
      hashType: props.hashType,
    })
  }
  return jsx(Router, {
    history: historyRef.current,
    children: props.children,
  })
}

/*
 * Copyright (c) 2023 Huawei Technologies Co.,Ltd.
 *
 * openInula is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *          http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
function BrowserRouter(props) {
  // 使用Ref持有History对象，防止重复渲染
  const historyRef = useRef()
  if (historyRef.current === null || historyRef.current === undefined) {
    historyRef.current = createBrowserHistory({
      basename: props.basename,
      forceRefresh: props.forceRefresh,
      getUserConfirmation: props.getUserConfirmation,
    })
  }
  return jsx(Router, {
    history: historyRef.current,
    children: props.children,
  })
}

const _excluded$1 = ['to', 'replace', 'component', 'onClick', 'target']
const isModifiedEvent = function (event) {
  return event.metaKey || event.altKey || event.ctrlKey || event.shiftKey
}
const checkTarget = function (target) {
  return !target || target === '_self'
}
function Link(props) {
  const to = props.to
  const replace = props.replace
  props.component
  const onClick = props.onClick
  const target = props.target
  const other = _objectWithoutPropertiesLoose(props, _excluded$1)
  const tag = props.tag || 'a'
  const context = useContext(RouterContext)
  const history = context.history
  const location = typeof to === 'function' ? to(context.location) : to
  let state
  let path
  if (typeof location === 'string') {
    path = parsePath(location)
  }
  else {
    const pathname = location.pathname
    const hash = location.hash
    const search = location.search
    path = {
      pathname,
      hash,
      search,
    }
    state = location.state
  }
  const href = history.createHref(path)
  const linkClickEvent = function (event) {
    try {
      if (onClick)
        onClick(event)
    }
    catch (e) {
      event.preventDefault()
      throw e
    }
    if (!event.defaultPrevented && event.button === 0 && checkTarget(target) && !isModifiedEvent(event)) {
      // 不是相同的路径执行push操作，是相同的路径执行replace
      const isSamePath = createPath(context.location) === createPath(path)
      const navigate = replace || isSamePath ? history.replace : history.push
      event.preventDefault()
      navigate(path, state)
    }
  }
  const linkProps = _extends({
    href,
    onClick: linkClickEvent,
  }, other)
  return Inula.createElement(tag, linkProps)
}

const _excluded = ['to', 'isActive']
function NavLink(props) {
  const to = props.to
  const isActive = props.isActive
  const rest = _objectWithoutPropertiesLoose(props, _excluded)
  const context = useContext(RouterContext)
  const toLocation = typeof to === 'function' ? to(context.location) : to
  const _ref = typeof toLocation === 'string' ? parsePath(toLocation) : toLocation
  const pathname = _ref.pathname
  const match = pathname ? matchPath(context.location.pathname, pathname) : null
  const isLinkActive = match && isActive ? isActive(match, context.location) : false
  const page = 'page'
  const otherProps = _extends({
    'aria-current': isLinkActive ? page : false,
  }, rest)
  return jsx(Link, _extends({
    to,
  }, otherProps))
}

export { BrowserRouter, HashRouter, Link, NavLink, Prompt, Redirect, Route, Router, Switch, RouterContext as __RouterContext, createBrowserHistory, createHashHistory, generatePath, matchPath, useHistory, useLocation, useParams, useRouteMatch, withRouter }
// # sourceMappingURL=router.js.map
